package com.wl.dzt.sys.core.dao.curd.validate;

import com.wl.dzt.sys.core.dao.DB;
import com.wl.dzt.sys.core.dao.select.Select;
import com.wl.dzt.sys.core.dao.select.term.Term;
import com.wl.dzt.sys.util.FieldUtil;
import com.wl.dzt.sys.util.SpringUtil;
import com.wl.dzt.sys.util.StringUtil;
import com.wl.dzt.sys.util.clazz.ClassUtil;
import org.springframework.cglib.beans.BeanMap;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;


/**
 * @author wl_code@163.com
 * @version 1.0
 * @date 2018/7/5/005
 * @description 验证对象
 * 用于传递验证参数
 */
public class Validate {

    /**
     * 表达式
     */
    private String exp;

    /**
     * spring bean
     */
    private Object springBean;

    /**
     * 关联类
     */
    private Class<?> refDeleteClass;

    /**
     * 错误信息 , 字段
     */
    private String error, field;

    public Validate() {
    }

    public Validate(String exp) {
        this.exp = exp;
    }

    /**
     * <b>把表达式转换为删除验证</b>
     * <p>
     * 根据所传递的类对象和关联字段对象进行一次删除之前的外键引用判断
     * </p>
     *
     * @param entity
     * @return
     */
    private Term toDelete(Object entity) {
        String exp = this.exp.replaceAll("!", "");
        String ary[] = exp.split("->");
        String id = BeanMap.create(entity).get("id").toString();
        Term term = new Term();
        term.setOp("=");
        term.setValue(id);
        term.setField(ary[1]);
        refDeleteClass = ClassUtil.createClass(ary[0]);
        return term;
    }

    /**
     * <b>把表达式转换为存在查询条件</b>
     * <p>
     * 添加或者修改之前根据所传递的表达式进行一次 字段是否存在重复的查询
     * </p>
     *
     * @param entity
     * @return
     */
    // 规则 id = ? ,id != 1
    private Term[] toExits(Object entity) {
        exp = exp.replaceAll(" {2,}", " ");
        String args[] = exp.split(",");
        List<Term> lst = new ArrayList<Term>();
        for (String arg : args) {
            String ary[] = arg.trim().split(" ");
            Term term = new Term();
            term.setField(ary[0]);
            term.setOp(ary[1]);
            term.setValue(ary.length == 2 ? null
                    : ("?".equals(ary[2]) ? FieldUtil.getFieldValueByCascade(term.getField(), entity) : ary[2]));
            lst.add(term);
        }
        String id = DB.getId(entity);
        if (id != null && !StringUtil.emptyStr(id)) {
            Term term = new Term();
            term.setField("id");
            term.setOp("!=");
            term.setValue(id);
            lst.add(term);
        }

        return lst.toArray(new Term[lst.size()]);
    }

    /**
     * <b>自定义验证</b>
     * <p>
     * 根据表达式转换为spring的bean方法
     * </p>
     *
     * @return
     */
    private Method toMethod() {
        String ary[] = exp.replaceAll("#", "").split("[.]");
        springBean = SpringUtil.getBean(ary[0]);
        try {
            Method method = springBean.getClass().getDeclaredMethod(ary[1], Object.class);
            return method;
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <b>字段存在验证</b>
     * <p>
     * 用于判断字段是否存在的验证
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean fieldExitsValidate(Object entity) {
        return DB.count(Select.create(entity.getClass()).where(this.toExits(entity))) <= 0;
    }

    /**
     * <b>spring 验证</b>
     * <p>
     * 根据规则自定义验证bean<br>
     * 规则如下 #beanName.methodName<br>
     * 参数必须为object,并且必须返回boolean<br>
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean springValidate(Object entity) {
        Method method = this.toMethod();
        try {
            return (boolean) method.invoke(this.springBean, entity);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * <b>删除引用验证</b>
     * <p>
     * 根据引用规则判断<br>
     * </p>
     *
     * @param entity
     * @return
     */
    public boolean deleteRefValidate(Object entity) {
        Term term = toDelete(entity);
        return DB.count(Select.create(refDeleteClass).where(term)) <= 0;
    }

    /**
     * <b>获取表达式第一个字符 </b>
     * <p>
     * 获取表达式第一个字符用于判断验证类型
     * </p>
     *
     * @return
     */
    public String getExpsFirst() {
        return exp.substring(0, 1);
    }

    public void setError(String error) {
        this.error = error;
    }

    public void setField(String field) {
        this.field = field;
    }

    public String getError() {
        return error;
    }

    public String getField() {
        return field;
    }

}
